home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / winsock / ircii2-6.zip / SRC\IRCII-2.6\SOURCE\HISTORY.C < prev    next >
C/C++ Source or Header  |  1994-12-28  |  12KB  |  540 lines

  1. /*
  2.  * history.c: stuff to handle command line history 
  3.  *
  4.  *
  5.  * Written By Michael Sandrof
  6.  *
  7.  * Copyright(c) 1990 
  8.  *
  9.  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
  10.  */
  11.  
  12. #ifndef lint
  13. static    char    rcsid[] = "@(#)$Id: history.c,v 1.6 1994/10/09 06:39:35 mrg Stab $";
  14. #endif
  15.  
  16. #include "irc.h"
  17.  
  18. #include "ircaux.h"
  19. #include "vars.h"
  20. #include "history.h"
  21. #include "output.h"
  22. #include "input.h"
  23.  
  24. static    int    parse_history();
  25.  
  26. static    FILE *hist_file = (FILE *)NULL;
  27.  
  28. typedef struct    HistoryStru
  29. {
  30.     int    number;
  31.     char    *stuff;
  32.     struct    HistoryStru *next;
  33.     struct    HistoryStru *prev;
  34. }    History;
  35.  
  36. /* command_history: pointer to head of command_history list */
  37. static    History *command_history_head = (History *)NULL;
  38. static    History *command_history_tail = (History *)NULL;
  39. static    History *command_history_pos = (History *)NULL;
  40.  
  41. /* hist_size: the current size of the command_history array */
  42. static    int    hist_size = 0;
  43.  
  44. /* hist_count: the absolute counter for the history list */
  45. static    int    hist_count = 0;
  46.  
  47. /*
  48.  * last_dir: the direction (next or previous) of the last get_from_history()
  49.  * call.... reset by add to history 
  50.  */
  51. static    int    last_dir = -1;
  52.  
  53. /*
  54.  * file_pos: The position in the history file of the last history entry
  55.  * zwooped out by get_from_history_file()... look there for how this is used 
  56.  */
  57. static    off_t    file_pos = 0;
  58.  
  59. /*
  60.  * history pointer
  61.  */
  62. static    History    *tmp = (History *)NULL;
  63.  
  64. /*
  65.  * history_match: using wild_match(), this finds the latest match in the
  66.  * history file and returns it as the function result.  Returns null if there
  67.  * is no match.  Note that this sticks a '*' at the end if one is not already
  68.  * there. 
  69.  */
  70. static    char    *history_match(match)
  71. char    *match;
  72. {
  73.     char    *ptr;
  74.     char    *match_str = (char *)NULL;
  75.  
  76.     if (*(match + strlen(match) - 1) == '*')
  77.         malloc_strcpy(&match_str, match);
  78.     else
  79.     {
  80.         match_str = (char *) new_malloc(strlen(match) + 2);
  81.         strcpy(match_str, match);
  82.         strcat(match_str, "*");
  83.     }
  84.     if (hist_file)
  85.     {
  86.         if (last_dir == -1)
  87.             fseek(hist_file, 0L, 2);
  88.         else
  89.             fseek(hist_file, file_pos, 0);
  90.         while (rfgets(buffer, BIG_BUFFER_SIZE, hist_file))
  91.         {
  92.             parse_history(buffer, &ptr);
  93.             if (wild_match(match_str, ptr))
  94.             {
  95.                 new_free(&match_str);
  96.                 *(ptr + strlen(ptr) - 1) = '\0';
  97.                 file_pos = ftell(hist_file);
  98.                 last_dir = PREV;
  99.                 return (ptr);
  100.             }
  101.         }
  102.         file_pos = 0;
  103.     }
  104.     if (!hist_file && get_int_var(HISTORY_VAR))
  105.     {
  106.         if ((last_dir == -1) || (tmp == (History *)NULL))
  107.             tmp = command_history_head;
  108.         else
  109.             tmp = tmp->next;
  110.         for (; tmp; tmp = tmp->next)
  111.             if (wild_match(match_str, tmp->stuff))
  112.             {
  113.                 new_free(&match_str);
  114.                 last_dir = PREV;
  115.                 return (tmp->stuff);
  116.             }
  117.     }
  118.     last_dir = -1;
  119.     new_free(&match_str);
  120.     return (char *)NULL;
  121. }
  122.  
  123. /*
  124.  * add_to_history_file: This adds the given line of text to the end of the
  125.  * history file using cnt as the history index number. 
  126.  */
  127. static    void    add_to_history_file(cnt, line)
  128. int    cnt;
  129. char    *line;
  130. {
  131.     if (hist_file)
  132.     {
  133.         fseek(hist_file, 0L, 2);
  134.         fprintf(hist_file, "%d: %s\n", cnt, line);
  135.         fflush(hist_file);
  136.         file_pos = ftell(hist_file);
  137.     }
  138. }
  139.  
  140. static    void    add_to_history_list(cnt, stuff)
  141. int    cnt;
  142. char    *stuff;
  143. {
  144.     History *new;
  145.  
  146.     if (get_int_var(HISTORY_VAR) == 0)
  147.         return;
  148.     if ((hist_size == get_int_var(HISTORY_VAR)) && command_history_tail)
  149.     {
  150.         if (hist_size == 1)
  151.         {
  152.             malloc_strcpy(&command_history_tail->stuff, stuff);
  153.             return;
  154.         }
  155.         new = command_history_tail;
  156.         command_history_tail = command_history_tail->prev;
  157.         command_history_tail->next = (History *)NULL;
  158.         new_free(&new->stuff);
  159.         new_free(&new);
  160.         if (command_history_tail == (History *)NULL)
  161.             command_history_head = (History *)NULL;
  162.     }
  163.     else
  164.         hist_size++;
  165.     new = (History *) new_malloc(sizeof(History));
  166.     new->stuff = (char *)NULL;
  167.     new->number = cnt;
  168.     new->next = command_history_head;
  169.     new->prev = (History *)NULL;
  170.     malloc_strcpy(&(new->stuff), stuff);
  171.     if (command_history_head)
  172.         command_history_head->prev = new;
  173.     command_history_head = new;
  174.     if (command_history_tail == (History *)NULL)
  175.         command_history_tail = new;
  176.     command_history_pos = (History *)NULL;
  177. }
  178.  
  179. /*
  180.  * set_history_file: this sets the file to be used by the command history
  181.  * function to whatever you send as file.  This expands twiddles and opens
  182.  * the file if all is well 
  183.  */
  184. void    set_history_file(file)
  185. char    *file;
  186. {
  187.     char    *ptr;
  188.     int    i,
  189.         cnt;
  190.     History *tmp;
  191.  
  192.     if (file)
  193.     {
  194. #ifdef DAEMON_UID
  195.         if (getuid() == DAEMON_UID)
  196.         {
  197.             say("You are not permitted to use a HISTORY_FILE");
  198.             set_string_var(HISTORY_FILE_VAR, (char *)NULL);
  199.             return;
  200.         }
  201. #endif /* DAEMON_UID */
  202.         if ((ptr = expand_twiddle(file)) == (char *)NULL)
  203.         {
  204.             say("Bad filename: %s",file);
  205.             set_string_var(HISTORY_FILE_VAR, (char *)NULL);
  206.             return;
  207.         }
  208.         set_string_var(HISTORY_FILE_VAR, ptr);
  209.         if (hist_file)
  210.             fclose(hist_file);
  211.         if ((hist_file = fopen(ptr, "w+")) == (FILE *)NULL)
  212.         {
  213.             say("Unable to open %s: %s", ptr, strerror(errno));
  214.             set_string_var(HISTORY_FILE_VAR, (char *)NULL);
  215.             hist_file = (FILE *)NULL;
  216.         }
  217.         else if (hist_size)
  218.         {
  219.             cnt = hist_size;
  220.             tmp = command_history_tail;
  221.             for (i = 0; i < cnt; i++, tmp = tmp->prev)
  222.                 add_to_history_file(tmp->number, tmp->stuff);
  223.         }
  224.         new_free(&ptr);
  225.     }
  226.     else if (hist_file)
  227.     {
  228.         fclose(hist_file);
  229.         hist_file = (FILE *)NULL;
  230.     }
  231. }
  232.  
  233. /*
  234.  * set_history_size: adjusts the size of the command_history to be size. If
  235.  * the array is not yet allocated, it is set to size and all the entries
  236.  * nulled.  If it exists, it is resized to the new size with a realloc.  Any
  237.  * new entries are nulled. 
  238.  */
  239. void    set_history_size(size)
  240. int    size;
  241. {
  242.     int    i,
  243.         cnt;
  244.     History *ptr;
  245.  
  246.     if (size < hist_size)
  247.     {
  248.         cnt = hist_size - size;
  249.         for (i = 0; i < cnt; i++)
  250.         {
  251.             ptr = command_history_tail;
  252.             command_history_tail = ptr->prev;
  253.             new_free(&(ptr->stuff));
  254.             new_free(&ptr);
  255.         }
  256.         if (command_history_tail == (History *)NULL)
  257.             command_history_head = (History *)NULL;
  258.         else
  259.             command_history_tail->next = (History *)NULL;
  260.         hist_size = size;
  261.     }
  262. }
  263.  
  264. /*
  265.  * parse_history: given a string of the form "number: stuff", this returns
  266.  * the number as an integer and points ret to stuff 
  267.  */
  268. static    int    parse_history(buffer, ret)
  269. char    *buffer;
  270. char    **ret;
  271. {
  272.     char    *ptr;
  273.     int    entry;
  274.  
  275.     if ((ptr = index(buffer, ':')) != NULL)
  276.     {
  277.         entry = atoi(buffer);
  278.         *ret = ptr + 2;
  279.         return (entry);
  280.     }
  281.     *ret = (char *)NULL;
  282.     return -1;
  283. }
  284.  
  285. /*
  286.  * add_to_history: adds the given line to the history array.  The history
  287.  * array is a circular buffer, and add_to_history handles all that stuff. It
  288.  * automagically allocted and deallocated memory as needed 
  289.  */
  290. void    add_to_history(line)
  291. char    *line;
  292. {
  293.     char    *ptr;
  294.  
  295.     if (line && *line)
  296.         while (line)
  297.         {
  298.             if ((ptr = sindex(line, "\n\r")) != NULL)
  299.                 *(ptr++) = '\0';
  300.             add_to_history_list(hist_count, line);
  301.             add_to_history_file(hist_count, line);
  302.             last_dir = PREV;
  303.             hist_count++;
  304.             line = ptr;
  305.         }
  306. }
  307.  
  308. static    char    *get_from_history_file(which)
  309. int    which;
  310. {
  311.     char    *ptr;
  312.  
  313.     if (last_dir == -1)
  314.         last_dir = which;
  315.     else if (last_dir != which)
  316.     {
  317.         last_dir = which;
  318.         get_from_history(which);
  319.     }
  320.     fseek(hist_file, file_pos, 0);
  321.     if (which == NEXT)
  322.     {
  323.         if (!fgets(buffer, BIG_BUFFER_SIZE, hist_file))
  324.         {
  325.             file_pos = 0L;
  326.             fseek(hist_file, 0L, 0);
  327.             if (!fgets(buffer, BIG_BUFFER_SIZE, hist_file))
  328.                 return (char *)NULL;
  329.         }
  330.     }
  331.     else if (!rfgets(buffer, BIG_BUFFER_SIZE, hist_file))
  332.     {
  333.         fseek(hist_file, 0L, 2);
  334.         file_pos = ftell(hist_file);
  335.         if (!rfgets(buffer, BIG_BUFFER_SIZE, hist_file))
  336.             return (char *)NULL;
  337.     }
  338.     file_pos = ftell(hist_file);
  339.     buffer[strlen(buffer) - 1] = '\0';
  340.     parse_history(buffer, &ptr);
  341.     return (ptr);
  342. }
  343.  
  344. static    char    *get_from_history_buffer(which)
  345. int    which;
  346. {
  347.     if ((get_int_var(HISTORY_VAR) == 0) || (hist_size == 0))
  348.         return (char *)NULL;
  349.     /*
  350.      * if (last_dir != which) { last_dir = which; get_from_history(which); }
  351.      */
  352.     if (which == NEXT)
  353.     {
  354.         if (command_history_pos)
  355.         {
  356.             if (command_history_pos->prev)
  357.                 command_history_pos = command_history_pos->prev;
  358.             else
  359.                 command_history_pos = command_history_tail;
  360.         }
  361.         else
  362.         {
  363.             add_to_history(get_input());
  364.             command_history_pos = command_history_tail;
  365.         }
  366.         return (command_history_pos->stuff);
  367.     }
  368.     else
  369.     {
  370.         if (command_history_pos)
  371.         {
  372.             if (command_history_pos->next)
  373.                 command_history_pos = command_history_pos->next;
  374.             else
  375.                 command_history_pos = command_history_head;
  376.         }
  377.         else
  378.         {
  379.             add_to_history(get_input());
  380.             command_history_pos = command_history_head;
  381.         }
  382.         return (command_history_pos->stuff);
  383.     }
  384. }
  385.  
  386. char    *get_from_history(which)
  387. int    which;
  388. {
  389.     char    *str = (char *)NULL;
  390.  
  391.     if (get_string_var(HISTORY_FILE_VAR))
  392.         str = get_from_history_file(which);
  393.     if (!str)
  394.         str = get_from_history_buffer(which);
  395.     return str;
  396. }
  397.  
  398. /* history: the /HISTORY command, shows the command history buffer. */
  399. /*ARGSUSED*/
  400. void    history(command, args)
  401. char    *command,
  402.     *args;
  403. {
  404.     int    cnt,
  405.         max;
  406.     char    *value;
  407.     History *tmp;
  408.  
  409.     say("Command History:");
  410.     if (hist_file)
  411.     {
  412.         if ((value = next_arg(args, &args)) != NULL)
  413.         {
  414.             if ((max = atoi(value)) > hist_count)
  415.                 max = 0;
  416.             else
  417.                 max = hist_count - max + 1;
  418.         }
  419.         else
  420.             max = 0;
  421.  
  422.         fseek(hist_file, 0L, 0);
  423.         while (--max > 0)
  424.             fgets(buffer, BIG_BUFFER_SIZE, hist_file);
  425.         while (fgets(buffer, BIG_BUFFER_SIZE, hist_file))
  426.         {
  427.             buffer[strlen(buffer) - 1] = '\0';
  428.             put_it("%s", buffer);
  429.         }
  430.     }
  431.     else if (get_int_var(HISTORY_VAR))
  432.     {
  433.         if ((value = next_arg(args, &args)) != NULL)
  434.         {
  435.             if ((max = atoi(value)) > get_int_var(HISTORY_VAR))
  436.                 max = get_int_var(HISTORY_VAR);
  437.         }
  438.         else
  439.             max = get_int_var(HISTORY_VAR);
  440.         for (tmp = command_history_tail, cnt = 0; tmp && (cnt < max);
  441.                 tmp = tmp->prev, cnt++)
  442.             put_it("%d: %s", tmp->number, tmp->stuff);
  443.     }
  444. }
  445.  
  446. /*
  447.  * do_history: This finds the given history entry in either the history file,
  448.  * or the in memory history buffer (if no history file is given). It then
  449.  * returns the found entry as its function value, or null if the entry is not
  450.  * found for some reason.  Note that this routine mallocs the string returned  
  451.  */
  452. char    *do_history(com, rest)
  453. char    *com;
  454. char    *rest;
  455. {
  456.     int    hist_num;
  457.     char    *ptr,
  458.         *ret = (char *)NULL;
  459.     static    char    *last_com = (char *)NULL;
  460.  
  461.     if (!com || !*com)
  462.     {
  463.         if (last_com)
  464.             com = last_com;
  465.         else
  466.             com = empty_string;
  467.     }
  468.     else
  469.         /*    last_dir = -1; */
  470.         malloc_strcpy(&last_com, com);
  471.  
  472.     if (!is_number(com))
  473.     {
  474.         if ((ptr = history_match(com)) != NULL)
  475.         {
  476.             if (rest && *rest)
  477.             {
  478.                 ret = (char *) new_malloc(strlen(ptr) +
  479.                     strlen(rest) + 2);
  480.                 strcpy(ret, ptr);
  481.                 strcat(ret, " ");
  482.                 strcat(ret, rest);
  483.             }
  484.             else
  485.                 malloc_strcpy(&ret, ptr);
  486.         }
  487.         else
  488.             say("No Match");
  489.         return (ret);
  490.     }
  491.     hist_num = atoi(com);
  492.     if (hist_file)
  493.     {
  494.         fseek(hist_file, 0L, 0);
  495.         while (fgets(buffer, BIG_BUFFER_SIZE, hist_file))
  496.             if (parse_history(buffer, &ptr) == hist_num)
  497.             {
  498.                 *(ptr + strlen(ptr) - 1) = '\0';
  499.                 if (rest && *rest)
  500.                 {
  501.                     ret = (char *) new_malloc(strlen(ptr)
  502.                         + strlen(rest) + 2);
  503.                     strcpy(ret, ptr);
  504.                     strcat(ret, " ");
  505.                     strcat(ret, rest);
  506.                 }
  507.                 else
  508.                     malloc_strcpy(&ret, ptr);
  509.                 last_dir = PREV;
  510.                 file_pos = ftell(hist_file);
  511.                 return (ret);
  512.             }
  513.         say("No such history entry: %d", hist_num);
  514.         file_pos = 0;
  515.     }
  516.     else
  517.     {
  518.         History *tmp;
  519.  
  520.         for (tmp = command_history_head; tmp; tmp = tmp->next)
  521.             if (tmp->number == hist_num)
  522.             {
  523.                 if (rest && *rest)
  524.                 {
  525.                     ret = (char *)
  526.                         new_malloc(strlen(tmp->stuff) +
  527.                         strlen(rest) + 2);
  528.                     strcpy(ret, tmp->stuff);
  529.                     strcat(ret, " ");
  530.                     strcat(ret, rest);
  531.                 }
  532.                 else
  533.                     malloc_strcpy(&ret, tmp->stuff);
  534.                 return (ret);
  535.             }
  536.         say("No such history entry: %d", hist_num);
  537.     }
  538.     return (char *)NULL;
  539. }
  540.